//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <core.h>
#include <_hal.h>
#include <_schedule.h>

//
// SyncObject
//
SyncObject::~SyncObject()
{
    bool_t bOriginalPreemption = DzDisablePreemption();
    if (NULL != m_pOwner) {
        m_pOwner->RemoveOwnedSyncObject(this);
        m_pOwner = NULL;
    }
    DzRestorePreemption(bOriginalPreemption);
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::SetOwner(Thread *pOwner)
{
    assert(pOwner);
    assert(NULL == m_pOwner);
    assert(!PreemptionEnabled());

    m_pOwner = pOwner;
    m_pOwner->AddOwnedSyncObject(this);
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::ClearOwner()
{
    assert(m_pOwner);
    assert(!PreemptionEnabled());

    m_pOwner->RemoveOwnedSyncObject(this);
    m_pOwner = NULL;
}

// IMPORTANT: When disable interrupt
void SyncObject::InsertWaiter(Thread *pWaiter)
{
    register Thread *pPrevWaiter;
    ForEachDLinkNodeReversely(Thread *, pPrevWaiter, &m_waitListHead) {
        if (!PriorityGreaterThan(pWaiter, pPrevWaiter)) {
            pPrevWaiter->InsertNext(pWaiter);
            return;
        }
    }

    m_waitListHead.InsertFirst(pWaiter);
}

// IMPORTANT: When own the m_waitListLock
void SyncObject::WillToInheritPriority(const Thread *pWaiter)
{
    assert(pWaiter);
    assert(m_pOwner);
    assert(!PreemptionEnabled());

    m_pOwner->m_lock.Lock();
    m_pOwner->WillToInheritPriority(pWaiter);
    m_pOwner->m_lock.Unlock();
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::WaiterReadyToUninterruptibleSleep()
{
    assert(!PreemptionEnabled());
    register Thread *pCurrentThread = GetCurrentThread();

    if (NULL != m_pOwner) WillToInheritPriority(pCurrentThread);

    pCurrentThread->m_lock.Lock();

    ReadyToUninterruptibleSleepOn(this);

    uint32_t uFlags = SaveFlagsAndCli();
    InsertWaiter(pCurrentThread);
    RestoreIF(uFlags);

    pCurrentThread->m_lock.Unlock();
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::WaiterReadyToUninterruptibleSleep(DzTimer *pBindingTimer)
{
    assert(pBindingTimer);
    assert(!PreemptionEnabled());

    register Thread *pCurrentThread = GetCurrentThread();

    if (NULL != m_pOwner) WillToInheritPriority(pCurrentThread);

    pCurrentThread->m_lock.Lock();

    ReadyToUninterruptibleSleepOn(this, pBindingTimer);

    uint32_t uFlags = SaveFlagsAndCli();
    pBindingTimer->_Start();
    InsertWaiter(pCurrentThread);
    RestoreIF(uFlags);

    pCurrentThread->m_lock.Unlock();
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::WaiterReadyToSleep(WaitResult *pResult)
{
    assert(pResult);
    assert(!PreemptionEnabled());
    register Thread *pCurrentThread = GetCurrentThread();

    if (NULL != m_pOwner) WillToInheritPriority(pCurrentThread);

    pCurrentThread->m_lock.Lock();

    ReadyToSleepOn(this, NULL, pResult);
    if (WaitResult_OK != *pResult) {
        pCurrentThread->m_lock.Unlock();
        return;
    }

    uint32_t uFlags = SaveFlagsAndCli();
    InsertWaiter(pCurrentThread);
    RestoreIF(uFlags);

    pCurrentThread->m_lock.Unlock();
}

// IMPORTANT: When own the m_waitListLock or disable preemption
void SyncObject::WaiterReadyToSleep(DzTimer *pBindingTimer,
    WaitResult *pResult)
{
    assert(pResult);
    assert(pBindingTimer);
    assert(!PreemptionEnabled());

    register Thread *pCurrentThread = GetCurrentThread();

    if (NULL != m_pOwner) WillToInheritPriority(pCurrentThread);

    pCurrentThread->m_lock.Lock();

    ReadyToSleepOn(this, pBindingTimer, pResult);
    if (WaitResult_OK != *pResult) {
        pCurrentThread->m_lock.Unlock();
        return;
    }

    uint32_t uFlags = SaveFlagsAndCli();
    pBindingTimer->_Start();
    InsertWaiter(pCurrentThread);
    RestoreIF(uFlags);

    pCurrentThread->m_lock.Unlock();
}

void SyncObject::WakeUpOneWaiter(register bool_t bWaiveInheritedPriority)
{
    m_waitListLock.Lock();
    uint32_t uFlags = SaveFlagsAndCli();
    if (!m_waitListHead.IsEmpty()) {
        register Thread *pWaiter = (Thread *)m_waitListHead.First();
        pWaiter->CancelBindingTimer();
        pWaiter->DetachFromSyncObject(this);
        RestoreIF(uFlags);

        pWaiter->ReadyToWakeUp();
        m_waitListLock.Unlock();

        if (!bWaiveInheritedPriority) Schedule();
    }
    else {
        RestoreIF(uFlags);
        m_waitListLock.Unlock();
    }

    if (bWaiveInheritedPriority) WaiveInheritedPriority();
}

void SyncObject::WakeUpSomeWaiters(register bool_t bWaiveInheritedPriority)
{
    m_waitListLock.Lock();
    uint32_t uFlags = SaveFlagsAndCli();
    while (!m_waitListHead.IsEmpty()) {
        register Thread *pWaiter = (Thread *)m_waitListHead.First();
        pWaiter->CancelBindingTimer();
        pWaiter->DetachFromSyncObject(this);
        RestoreIF(uFlags);

        ECode ec = pWaiter->ReadyToWakeUp();
        m_waitListLock.Unlock();

        if (!bWaiveInheritedPriority) Schedule();

        if (NOERROR == ec) goto Exit;

        m_waitListLock.Lock();
        uFlags = SaveFlagsAndCli();
    }
    RestoreIF(uFlags);
    m_waitListLock.Unlock();

Exit:
    if (bWaiveInheritedPriority) {
    	if (!PreemptionEnabled()) {
            WaiveInheritedPriority(FALSE);
        } else {
            WaiveInheritedPriority(TRUE);
        }
    }
}

void SyncObject::WakeUpAllWaiters(register bool_t bWaiveInheritedPriority)
{
    m_waitListLock.Lock();
    uint32_t uFlags = SaveFlagsAndCli();
    while (!m_waitListHead.IsEmpty()) {
        register Thread *pWaiter = (Thread *)m_waitListHead.First();
        pWaiter->CancelBindingTimer();
        pWaiter->DetachFromSyncObject(this);
        RestoreIF(uFlags);

        pWaiter->ReadyToWakeUp();
        m_waitListLock.Unlock();

        if (!bWaiveInheritedPriority) Schedule();

        m_waitListLock.Lock();
        uFlags = SaveFlagsAndCli();
    }
    RestoreIF(uFlags);
    m_waitListLock.Unlock();

    if (bWaiveInheritedPriority) WaiveInheritedPriority();
}

// IMPORTANT: when disable preemption
void SyncObject::BeginToWakeUpSomeWaiters()
{
    assert(!PreemptionEnabled());
    uint32_t uFlags = SaveFlagsAndCli();
    while (!m_waitListHead.IsEmpty()) {
        register Thread *pWaiter = (Thread *)m_waitListHead.First();
        pWaiter->CancelBindingTimer();
        pWaiter->DetachFromSyncObject(this);
        RestoreIF(uFlags);

        ECode ec = pWaiter->ReadyToWakeUp();

        if (NOERROR == ec) return;

        uFlags = SaveFlagsAndCli();
    }
    RestoreIF(uFlags);
}

// IMPORTANT: when disable interrupt
void SyncObject::DetachWaiter(Thread *pWaiter)
{
    assert(pWaiter);
    assert(this == pWaiter->m_pWaitingSyncObject);

    pWaiter->DetachFromSyncObject(this);
}

Thread *SyncObject::GetPriorityHighestWaiter()
{
    m_waitListLock.Lock();
    Thread *pWaiter =
        m_waitListHead.IsEmpty()? NULL : (Thread *)m_waitListHead.First();
    m_waitListLock.Unlock();

    return pWaiter;
}

// TODO: To be remove
#ifdef _EVC
EXTERN_C int atexit(
    void (__cdecl *func)(void)
    )
{
    return 0;
}
#endif
